package com.guimin.user.api;

import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.guimin.common.util.AliyunSmsUtil;
import com.guimin.common.util.NetworkUtil;
import com.guimin.common.util.exception.BaseException;
import com.guimin.common.vo.R;
import com.guimin.user.dao.UserInfoDao;
import com.guimin.user.dto.LoginInfoDto;
import com.guimin.user.dto.UpdateUserDto;
import com.guimin.user.entity.UserInfo;
import com.guimin.user.service.UserInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@RestController
@Slf4j
@CrossOrigin
@Validated
public class UserInfoApi {
    /**
     * redis
     */
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private UserInfoDao userInfoDao;
    /**
     * user实现类
     */
    @Resource
    private UserInfoService userInfoService;

    /**
     * 验证码,验证码成功
     */
    private static final String VERIFY = "verify";
    private static final String VERIFIED = "verifyed";

    public LoginInfoDto getLogin(HttpServletRequest request) {
        Object token = redisTemplate.opsForValue().get("token" + request.getHeader("token"));
        if (token instanceof LoginInfoDto) {
            return (LoginInfoDto) token;
        } else {
            System.out.println(token+"\n"+request.getHeader("token"));
            throw new BaseException("登录已失效");
        }
    }

    /**
     * 发送验证码
     *
     * @param phone 手机号
     * @param type  短信类型(0-注册短信,1-找回密码短信)
     * @return 结果集
     */
    @GetMapping("/send/code")
    public R<String> sendVerifyCode(@RequestParam @Size(min = 11, max = 11, message = "手机号的长度必须是11位") String phone,
                                    @RequestParam @NotNull Integer type) {
        //生成验证码
        String verifyCode = String.format("%04d", new Random().nextInt(9999));
        //验证是否是手机号
        //...
        //发送验证码
        if (false) {//设置为false,开发环境用
            try {
                R<String> result;
                if (type == 0) {
                    //注册短信
                    result = AliyunSmsUtil.sendVerifyCodeOfRegister(phone, verifyCode);
                } else if (type == 1) {
                    //找回密码短信
                    result = AliyunSmsUtil.sendVerifyCodeOfRetrievePwd(phone, verifyCode);
                } else {
                    return R.fail("未知短信类型type=" + type);
                }
                if (!result.success) {
                    log.info("[阿里云短信]短信发送失败\n配置参数 --> {}\n响应参数 <-- {}"
                            , result.getMessage(), result.getData());
                    return R.fail("短信发送失败,请确保您的手机号可以正常使用");
                }
            } catch (ClientException e) {
                log.warn("[阿里云短信]客户端异常,短信无法发送:配置参数 --> {}", e.getMessage(), e);
                return R.fail("短信暂时无法发送,请稍后再试");
            } catch (Exception e) {
                return R.fail("验证码发送失败");
            }
        } else {
            log.info("验证码已发送，注意查收，手机号：" + phone + ",验证码：" + verifyCode);
        }
        //将手机号，验证码，有效时间放入redis,设置验证码有效时间：5min
        redisTemplate.opsForValue().set(VERIFY + phone, verifyCode, 5, TimeUnit.MINUTES);
        return R.success("验证码已发送，注意查收");
    }


    @PostMapping("/test/u")
    public String testDemo(@RequestBody LoginInfoDto dto) {
        System.out.println(dto);
        if (dto.getPhone().equals("18777188604")) {
            return "true";
        } else {
            return "false";
        }

    }

    /**
     * 账号是否已经注册
     *
     * @param phone 手机号
     * @return 结果集
     */
    @GetMapping("/u/exist")
    public R<String> phoneIsExist(@RequestParam @NotBlank(message = "手机号不能为空") @Size(min = 11, max = 11, message = "手机号的长度必须是11位") String phone) {
        if (userInfoService.userIsExist
                (phone)) {
            return R.success("手机号已注册");
        }
        return R.fail("手机号未注册");
    }


    /**
     * 登录
     *
     * @return
     */
    @PostMapping("/gm/code/login")
    public R<String> loginSty(@RequestBody @Validated LoginInfoDto loginDto, HttpServletRequest request, HttpServletResponse response, @RequestParam String VerifyCode) {
        System.out.println("前端参数：\n" + VerifyCode);
        if (loginDto.getPhone() == null || loginDto.getPhone() == "") {
            throw new BaseException("手机号码不能为空");
        }
        if (VerifyCode == null || VerifyCode == "") {
            throw new BaseException("验证码为空");
        }
        //检验验证码
        {
            //手机号校验
            String code = (String) redisTemplate.opsForValue().get(VERIFY + loginDto.getPhone());
            System.out.println("redis验证码:" + code);
            if (code == null) {
                return R.fail("验证码已过期");
            } else if (!code.equals(VerifyCode)) {
                return R.fail("验证码错误");
            } else {
                redisTemplate.delete(VERIFY + loginDto.getPhone());
                //设置验证成功的有效时间：5min
                redisTemplate.opsForValue().set(VERIFIED + loginDto.getPhone(), "true", 5, TimeUnit.MINUTES);

            }
        }

        //校验手机号是否注册过
        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("phone", loginDto.getPhone());
        UserInfo userInfo = userInfoDao.selectOne(wrapper);

        //手机号已注册
        if (userInfo != null) {

            try {
                //进行登录
                loginDto.setLoginIpAddress(NetworkUtil.getIpAddress(request));
                LoginInfoDto login = userInfoService.login(loginDto);
                //生成token
                String token = Base64.encodeBase64String(UUID.randomUUID().toString().replace("-", "").getBytes(StandardCharsets.UTF_8));
                //设置登录有效期为5天
                redisTemplate.opsForValue().set("token" + token, login, 365, TimeUnit.DAYS);

                //设置cookie时间为一年
                Cookie cookie = new Cookie("cookieName", "value");
                cookie.setMaxAge(60 * 60 * 24 * 365);//一年
                response.addCookie(cookie);
                if(userInfo.getRole().equals("ADMIN")){
                    return R.success("200","登录成功", token);//管理员登录
                }
                else if(userInfo.getRole().equals("AGENT")){
                    return R.success("900","登录成功", token);//站长登录
                }
                else if(userInfo.getRole().equals("PROPERTY")){
                    return R.success("800","登录成功", token);//物业登录
                }
                else {
                    return R.success("600","登录成功", token);//业主登录
                }
            } catch (BaseException be) {
                return R.fail(be.getMessage());
            }

        }
        //未注册
        else {
            UserInfo register = userInfoService.register(loginDto);
            LoginInfoDto infoDto = new LoginInfoDto();
            infoDto.setPhone(register.getPhone());
            if (register != null) {
                try {
                    //进行登录
                    infoDto.setLoginIpAddress(NetworkUtil.getIpAddress(request));
                    LoginInfoDto login = userInfoService.login(infoDto);
                    //生成token
                    String token = Base64.encodeBase64String(UUID.randomUUID().toString().replace("-", "").getBytes(StandardCharsets.UTF_8));
                    //设置登录有效期为5天
                    redisTemplate.opsForValue().set("token" + token, login, 365, TimeUnit.DAYS);

                    //设置cookie时间为一年
                    Cookie cookie = new Cookie("cookieName", "value");
                    cookie.setMaxAge(60 * 60 * 24 * 365);
                    response.addCookie(cookie);

                    //redisTemplate.opsForValue().set(infoDto.getPhone(),token,5,TimeUnit.DAYS);
                    return R.success("登录成功", token);
                } catch (BaseException be) {
                    return R.fail(be.getMessage());
                }
            } else {
                return R.fail("登录失败");
            }
        }
    }


    /**
     * 管理员登录
     *
     * @param loginDto
     * @param request
     * @param response
     * @return
     */
    @PostMapping("/admin/login")
    public R<String> adminLogin(@RequestBody @Validated LoginInfoDto loginDto, HttpServletRequest request, HttpServletResponse response) {
        if (loginDto.getPhone() == null) {
            throw new BaseException("手机号为空");
        }
        if (loginDto.getPass() == null) {
            throw new BaseException("管理员密码为空");
        }
        try {
            QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("phone", loginDto.getPhone());
            queryWrapper.eq("pass", loginDto.getPass());
            queryWrapper.eq("role", "ADMIN");
            UserInfo userInfo = userInfoDao.selectOne(queryWrapper);
            if (userInfo == null) {
                return R.fail("您不是管理员");
            }
            try {
                //进行登录
                loginDto.setLoginIpAddress(NetworkUtil.getIpAddress(request));
                LoginInfoDto login = userInfoService.login(loginDto);
                //生成token
                String token = Base64.encodeBase64String(UUID.randomUUID().toString().replace("-", "").getBytes(StandardCharsets.UTF_8));
                //设置登录有效期为5天
                redisTemplate.opsForValue().set("token" + token, login, 365, TimeUnit.DAYS);

                //设置cookie时间为一年
                Cookie cookie = new Cookie("adminLoginState", "value");
                cookie.setMaxAge(60 * 60 * 24 * 365);
                response.addCookie(cookie);

                //redisTemplate.opsForValue().set(infoDto.getPhone(),token,5,TimeUnit.DAYS);
                return R.success("登录成功", token);
            } catch (BaseException be) {
                System.out.println("登录失败原因：" + be.getMessage());
                return R.fail("管理员登录失败");
            }

        } catch (Exception e) {
            return R.fail("您不是管理员");
        }

    }


    /**
     * 退出登录
     *
     * @return 结果集
     */
    @GetMapping("/logout")
    public R<String> logout(HttpServletRequest request, @RequestParam String phone) {
        redisTemplate.delete("token" + request.getHeader("token"));
        redisTemplate.delete(phone);
        return R.success("已退出登录");
    }

    /**
     * 获取用户信息
     *
     * @param request
     * @return
     */
    @GetMapping("/user/get/info")
    public R<UserInfo> getUserInfo(HttpServletRequest request) {
        LoginInfoDto login = getLogin(request);
        UserInfo u = userInfoService.getById(login.getId());
        return u != null ? R.success(null, u) : R.fail("获取失败");
    }

    /**
     * 获取用户信息
     *
     * @param request
     * @return
     */
    @PutMapping("/user/update/info")
    public R<UserInfo> updateUserInfo(HttpServletRequest request, @RequestBody UpdateUserDto dto) {
        LoginInfoDto login = getLogin(request);
        boolean update = userInfoService.update(new UserInfo()
                        .setNickname(dto.getNickname())
                        .setAge(dto.getAge())
                        .setGender(dto.getGender())
                        .setUpdateDatetime(new Date())
                , new LambdaQueryWrapper<UserInfo>()
                        .eq(UserInfo::getId, login.getId()));
        return update ? R.success("修改成功") : R.fail("修改失败");
    }

}
